<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Defines the editing form for the cppexpression question type.
 *
 * @package     cppexpression
 * @author      Khrzhanovskaya Olga, Sychev Oleg
 * @copyright   &copy; 2014 Oleg Sychev, Volgograd State Technical University
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */


defined('MOODLE_INTERNAL') || die();

global $CFG;
require_once($CFG->dirroot . '/question/type/shortanswer/edit_shortanswer_form.php');
require_once($CFG->dirroot . '/question/type/cppexpression/questiontype.php');

/**
 * Cppexpression question editing form definition.
 */
class qtype_cppexpression_edit_form extends qtype_shortanswer_edit_form {

    // init hints options
    private $stackanalyzeroptions = array();
    private $algebraanalyzeroptions = array();

    private $hintanalyzers = array();

    protected function definition_inner($mform) {

        global $CFG;
        global $PAGE;

        $qtype = new qtype_cppexpression;

        $graderanalyzernames = $qtype->get_grading_analyzers_names();
        $hintanalyzernames = $qtype->get_hint_analyzers_names();

        foreach($hintanalyzernames as $name => $description) {
            $classname = "\\qtype_cppexpression\\{$name}\\{$name}_hint";
            // Options.
            $options = $classname::hint_modes();
            $options[0] = get_string('cppexpr_hintno', 'qtype_cppexpression');// Adding standard 'No' option.

            $this->hintanalyzers[] = array('name' => $name,
                                    'description' => $description,
                                    'modefieldname' => $name . 'mode',
                                    'options' => $options,
                                    'penaltyfieldname' => $name . 'penalty',
                                    'penaltyfieldnameinteractive' => $name . 'interactive');
        }

        $mform->addElement('textarea', 'declarations', get_string('form_declarations', 'qtype_cppexpression'), 'wrap="virtual" rows="5" cols="80"');
        $mform->setType('declarations', PARAM_TEXT);

        // Grading analyzer selector.
        mform->addElement('select', 'gradinganalyzer', get_string('form_gradinganalyzer', 'qtype_cppexpression'), $graderanalyzernames);
        $mform->addElement('text', 'hintgradeborder', get_string('form_gradeborder', 'qtype_cppexpression'));
        $mform->setType('hintgradeborder', PARAM_FLOAT);
        $mform->setDefault('hintgradeborder', '0.9');

        // Hints.
        $mform->addElement('header', 'multitriesheader', get_string('form_analyzersheader', 'qtype_cppexpression'));
        $mform->setExpanded('multitriesheader', 1);

        foreach($this->hintanalyzers as $hintanalyzer){
            $mform->addElement('select', $hintanalyzer['modefieldname'],
                get_string('form_'.$hintanalyzer['modefieldname'], 'qtype_cppexpression'),
                $hintanalyzer['options']);
            $mform->addElement('text', $hintanalyzer['penaltyfieldname'], get_string('form_penalty', 'qtype_cppexpression', $description));
            $mform->setType($hintanalyzer['penaltyfieldname'], PARAM_FLOAT);
            $mform->setDefault($hintanalyzer['penaltyfieldname'], '0.333333');

        }

        $mform->addElement('static', 'answersinstruct',
                get_string('correctanswers', 'qtype_shortanswer'),
                get_string('form_answerinstruct', 'qtype_cppexpression'));
        $mform->closeHeaderBefore('answersinstruct');

        $this->add_per_answer_fields($mform, get_string('cppexpr_answer', 'qtype_cppexpression'), question_bank::fraction_options());
        $this->add_interactive_settings();
    }

    protected function get_hint_fields($withclearwrong = false, $withshownumpartscorrect = false) {
        $mform = $this->_form;
        list($repeated, $repeatedoptions) = parent::get_hint_fields($withclearwrong, $withshownumpartscorrect);

        //$langselect = $mform->getElement('langid');
        //$langs = $langselect->getSelected();
        //$langobj = block_formal_langs::lang_object($langs[0]);
        foreach($this->hintanalyzers as $hintanalyzer) {
            $repeated[] = $mform->createElement('select', $hintanalyzer['interactive'],
                get_string('form_'.$hintanalyzer['modefieldname'], 'qtype_cppexpression'),
                $hintanalyzer['options']);
        }
        return array($repeated, $repeatedoptions);
    }
//TODO - check and make sure hint fields are filled correctly.
    protected function data_preprocessing_hints($question, $withclearwrong = false,
                                                $withshownumpartscorrect = false) {
        if (empty($question->hints)) {
            return $question;
        }
        $question = parent::data_preprocessing_hints($question, $withclearwrong, $withshownumpartscorrect);

        $qtype = new qtype_cppexpression;
        $hintanalyzernames = $qtype->get_hint_analyzers_names();

        $hintsoptions = array();
        /*foreach ($question->hints as $hint) {
            $options = explode('\n',$hint->options);
            foreach($options as $option) {
                list($hintkey,$hintanalyzermode) = explode('_',$option);
                foreach($hintanalyzernames as $hintanalyzername) {
                    if($hintkey == $hintanalyzername){
                        $hintsoptions[$hintkey][] = $hintanalyzermode;
                    }
                }
            }
        }*/

        foreach($hintanalyzernames as $hintanalyzername) {
            foreach ($question->hints as $hint) {
                $options = explode('\n',$hint->options);
                if( strpos($hint->options, $hintanalyzername) === false) {
                    $hintsoptions[$hintanalyzername][] = 0;
                }
                else {
                    foreach($options as $option) {
                        list($hintkey,$hintanalyzermode) = explode('_',$option);
                        if($hintkey == $hintanalyzername){
                            $hintsoptions[$hintanalyzername][] = $hintanalyzermode;
                        }

                    }
                }
            }
        }

        /*echo '<pre>';
        print_r($hintsoptions);
        echo '<pre>';
        */
        foreach($hintsoptions as $key => $value) {
            $fieldname =  $key.'interactive';
            $question->$fieldname = $value;
        }

        return $question;
    }

    protected function get_more_choices_string() {
        return get_string('addmorechoiceblanks', 'question');
    }

    protected function data_preprocessing($question) {
        $question = parent::data_preprocessing($question);
        $question = $this->data_preprocessing_hints($question);
        return $question;
    }
//TODO - cleanup this function.
    public function validation($data, $files) {
        global $CFG;
        $errors = parent::validation($data, $files);

        if (!array_key_exists('hintgradeborder', $data)) {
            $data['hintgradeborder'] = 0;
        }
        else if(!is_numeric($data['hintgradeborder']) ||
            $data['hintgradeborder'] > 1 || $data['hintgradeborder'] < 0) {
            $errors['hintgradeborder'] = get_string('form_errorhintgradeborder', 'qtype_cppexpression');
        }

        $qtype = new qtype_cppexpression;
        $hintanalyzernames = $qtype->get_hint_analyzers_names();
        $graderanalyzernames = $qtype->get_grader_analyzers_names();

        foreach($hintanalyzernames as $name) {
            $fieldname = $name . 'penalty';
            if (!array_key_exists($fieldname, $data)) {
                $data[$fieldname] = 0;
            }
            else if(!is_numeric($data[$fieldname]) ||
                $data[$fieldname] > 1 || $data[$fieldname] < 0) {
                $errors[$fieldname] = get_string('form_errorpenalty', 'qtype_cppexpression');
            }
        }

        // TODO: add checking codedescription (when cpp-parser will exist)

        $answercount = 0;
        $answers = $data['answer'];

        $maxerrors = 5;
        if (isset($CFG->qtype_cppexpression_maxerrorsshown)) {
            $maxerrors = $CFG->qtype_cppexpression_maxerrorsshown;
        }

        // Fill accepting errors array.
        foreach ($answers as $key => $answer) {
            $trimmedanswer = trim($answer);
            $elementname = "answer[$key]";
            $acceptingerrors = array();
            if ($trimmedanswer !== '') {
                $answercount++;

                // Hints accepting check.
                foreach($hintanalyzernames as $name) {
                    $fieldname = $name . 'mode';
                    $isusedinteractive = $this->is_used_analyser_interactive($data, $fieldname);

                    if($data[$fieldname] != 0 || $isusedinteractive) { // When mode is 0 hint is disabled.
                        $classname = "\\qtype_cppexpression\\{$name}\\{$name}_hint";
                        $accept = $classname::accept_expression($answer);
                        $acceptingerrors = array_merge($acceptingerrors, $accept);
                    }
                }

                // Grading accepting check.
                $name = $data['gradinganalyzer'];
                $classname = "\\qtype_cppexpression\\{$name}\\{$name}_grader";
                $accept = $classname::can_accept_answer($answer);
                $acceptingerrors = array_merge($acceptingerrors, $accept);

                // Now get error messages from errors (no more than limit).
                if (!empty($acceptingerrors)) {
                    $i = 0;
                    $errors[$elementname] = '';
                    foreach ($acceptingerrors as $error) {
                        if ($i < $maxerrors) {
                            $errors[$elementname] .= $error->error_message();
                        }
                        $i++;
                    }
                    if ($i > $maxerrors) {
                        $errors[$elementname] .=  get_string('form_toomanyerrors', 'qtype_cppexpression' , $i - $maxerrors);
                    }
                }
            }
        }


        return $errors;
    }

    /**
     * Detect: can analyser be used in interactive mode.
     * @param $data data on the edit_form
     * @param $analysername name of analyser: to get field of using mode for interactive
     * @return bool* using
     */
    private function is_used_analyser_interactive ($data, $analysername){
        $i = 0;
        $fieldname = $analysername . 'interactive';

        foreach($data['hint'] as $hint) {
            if($hint['text'] != ''){
                $fielddata = $data[$fieldname];
                if($fielddata[$i] != 0){
                    return true;
                }
            }
            $i++;
        }
        return false;
    }

    public function qtype() {
        return 'cppexpression';
    }

}
